﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Windows.Data.Xml.Dom;
using Windows.Storage;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;

// The data model defined by this file serves as a representative example of a strongly-typed
// model that supports notification when members are added, removed, or modified.  The property
// names chosen coincide with data bindings in the standard item templates.
//
// Applications may use this model as a starting point and build on it, or discard it entirely and
// replace it with something appropriate to their needs.

namespace Enterprise_Store.Data
{
    /// <summary>
    /// Base class for <see cref="SampleDataItem"/> and <see cref="SampleDataGroup"/> that
    /// defines properties common to both.
    /// </summary>
    [Windows.Foundation.Metadata.WebHostHidden]
    public abstract class SampleDataCommon : Enterprise_Store.Common.BindableBase
    {
        private static Uri _baseUri = new Uri("ms-appx:///");

        public SampleDataCommon(String uniqueId, String title, String subtitle, String imagePath, String description)
        {
            this._uniqueId = uniqueId;
            this._title = title;
            this._subtitle = subtitle;
            this._description = description;
            this._imagePath = imagePath;
            this._uriErrorMessage = string.Empty;
            this._height = 200;
        }

        public Boolean DisplayError
        {
            get
            {
                return _uriErrorMessage != string.Empty;
            }
        }

        private bool _errorAlreadyDisplayed = false;
        public Boolean ErrorAlreadyDisplayed
        {
            get
            {
                return !_errorAlreadyDisplayed;
            }
            set { this.SetProperty(ref this._errorAlreadyDisplayed,value);}
        }

        private int _height;
        public int Height
        {
            get
            {
                return this._height;
            }
            set { this.SetProperty(ref this._height, value); }
        }

        private string _uriErrorMessage = string.Empty;
        public string UriErrorMessage
        {
            get { return this._uriErrorMessage; }
            set
            {
                this.SetProperty(ref this._uriErrorMessage, value); 
            }
        }


        private string _uniqueId = string.Empty;
        public string UniqueId
        {
            get { return this._uniqueId; }
            set { this.SetProperty(ref this._uniqueId, value); }
        }

        private string _title = string.Empty;
        public string Title
        {
            get { return this._title; }
            set { this.SetProperty(ref this._title, value); }
        }

        private string _subtitle = string.Empty;
        public string Subtitle
        {
            get { return this._subtitle; }
            set { this.SetProperty(ref this._subtitle, value); }
        }

        private string _description = string.Empty;
        public string Description
        {
            get { return this._description; }
            set { this.SetProperty(ref this._description, value); }
        }

        private ImageSource _image = null;
        private String _imagePath = null;

        public String ImagePath
        {
            get
            {
                return _imagePath;
            }
        }

        public ImageSource Image
        {
            get
            {
                if (this._image == null && this._imagePath != null)
                {
                    this._image = new BitmapImage(new Uri(SampleDataCommon._baseUri, this._imagePath));
                    
                }
                return this._image;
            }

            set
            {
                this._imagePath = null;
                this.SetProperty(ref this._image, value);
            }
        }

        public void SetImage(String path)
        {
            this._image = null;
            this._imagePath = path;
            this.OnPropertyChanged("Image");
        }

        public override string ToString()
        {
            return this.Title;
        }
    }

    /// <summary>
    /// Generic item data model.
    /// </summary>
    public class SampleDataItem : SampleDataCommon
    {
        public SampleDataItem(String uniqueId, String title, String subtitle, String imagePath, String description, String content, SampleDataGroup group)
            : base(uniqueId, title, subtitle, imagePath, description)
        {
            this._content = content;
            this._group = group;
        }

        private string _content = string.Empty;
        public string Content
        {
            get { return this._content; }
            set { this.SetProperty(ref this._content, value); }
        }

        private SampleDataGroup _group;
        public SampleDataGroup Group
        {
            get { return this._group; }
            set { this.SetProperty(ref this._group, value); }
        }
    }

    /// <summary>
    /// Generic group data model.
    /// </summary>
    public class SampleDataGroup : SampleDataCommon, IEqualityComparer<SampleDataGroup>
    {
        public SampleDataGroup(String uniqueId, String title, String subtitle, String imagePath, String description)
            : base(uniqueId, title, subtitle, imagePath, description)
        {
            Items.CollectionChanged += ItemsCollectionChanged;
        }

        private void ItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            // Provides a subset of the full items collection to bind to from a GroupedItemsPage
            // for two reasons: GridView will not virtualize large items collections, and it
            // improves the user experience when browsing through groups with large numbers of
            // items.
            //
            // A maximum of 12 items are displayed because it results in filled grid columns
            // whether there are 1, 2, 3, 4, or 6 rows displayed

            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    if (e.NewStartingIndex < 12)
                    {
                        TopItems.Insert(e.NewStartingIndex,Items[e.NewStartingIndex]);
                        if (TopItems.Count > 12)
                        {
                            TopItems.RemoveAt(12);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Move:
                    if (e.OldStartingIndex < 12 && e.NewStartingIndex < 12)
                    {
                        TopItems.Move(e.OldStartingIndex, e.NewStartingIndex);
                    }
                    else if (e.OldStartingIndex < 12)
                    {
                        TopItems.RemoveAt(e.OldStartingIndex);
                        TopItems.Add(Items[11]);
                    }
                    else if (e.NewStartingIndex < 12)
                    {
                        TopItems.Insert(e.NewStartingIndex, Items[e.NewStartingIndex]);
                        TopItems.RemoveAt(12);
                    }
                    break;
                case NotifyCollectionChangedAction.Remove:
                    if (e.OldStartingIndex < 12)
                    {
                        TopItems.RemoveAt(e.OldStartingIndex);
                        if (Items.Count >= 12)
                        {
                            TopItems.Add(Items[11]);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Replace:
                    if (e.OldStartingIndex < 12)
                    {
                        TopItems[e.OldStartingIndex] = Items[e.OldStartingIndex];
                    }
                    break;
                case NotifyCollectionChangedAction.Reset:
                    TopItems.Clear();
                    while (TopItems.Count < Items.Count && TopItems.Count < 12)
                    {
                        TopItems.Add(Items[TopItems.Count]);
                    }
                    break;
            }
        }

        private ObservableCollection<SampleDataItem> _items = new ObservableCollection<SampleDataItem>();
        public ObservableCollection<SampleDataItem> Items
        {
            get { return this._items; }
        }

        private ObservableCollection<SampleDataItem> _topItem = new ObservableCollection<SampleDataItem>();
        public ObservableCollection<SampleDataItem> TopItems
        {
            get {return this._topItem; }
        }

        public bool Equals(SampleDataGroup a, SampleDataGroup b)
        {
            return a.Title == b.Title;
        }

        public int GetHashCode(SampleDataGroup obj)
        {
            return obj.Title.GetHashCode();
        }
    }

    /// <summary>
    /// Creates a collection of groups and items with hard-coded content.
    /// 
    /// SampleDataSource initializes with placeholder data rather than live production
    /// data so that sample data is provided at both design-time and run-time.
    /// </summary>
    public sealed class SampleDataSource
    {
        private static SampleDataSource _sampleDataSource = new SampleDataSource();
        internal static StorageFile file = null;

        private static String _error = null;

        private ObservableCollection<SampleDataGroup> _allGroups = new ObservableCollection<SampleDataGroup>();
        public ObservableCollection<SampleDataGroup> AllGroups
        {
            get { return this._allGroups; }
        }

        public static IEnumerable<SampleDataGroup> GetGroups(string uniqueId)
        {
            if (!uniqueId.Equals("AllGroups")) throw new ArgumentException("Only 'AllGroups' is supported as a collection of groups");
            
            return _sampleDataSource.AllGroups;
        }

        public static SampleDataGroup GetGroup(string uniqueId)
        {
            // Simple linear search is acceptable for small data sets
            var matches = _sampleDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }

        public static SampleDataItem GetItem(string uniqueId)
        {
            // Simple linear search is acceptable for small data sets
            var matches = _sampleDataSource.AllGroups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }

        public SampleDataSource()
        {
            loadData();
        }

        private async void loadData()
        {
            XmlNodeList applicationGroups = null;
            SampleDataGroup group;
            int cptApplicationGroups = 0, cptApplication = 0;

            if(file == null)
            {
                try
                {
                    file = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(App.ConfigurationFile);
                }
                catch (FileNotFoundException)
                {

                }

                //If there is no configuration file on the default location, read a demo one on the application package.
                // this is mostly used for a demo app in the Windows Store
                if (file == null)
                {
                    try
                    {
                        file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Assets\StoreStructure.xml");
                    }
                    catch (FileNotFoundException)
                    {

                    }
                }
            }

            if (file != null)
            {
                XmlDocument doc = null;

                try
                {
                    doc = await XmlDocument.LoadFromFileAsync(file);

                    if (doc != null)
                    {
                        applicationGroups = doc.SelectNodes("//xml/ApplicationGroup");
                        cptApplicationGroups = applicationGroups.Count;
                    }
                    
                }
                catch (Exception)
                {
                    _error = App.errorXMLEncoding;
                    return;
                }

                
                if (applicationGroups != null)
                {
                    XmlNodeList nodeList = null;
                    String nameGroup = "", descriptionGroup = "", imageGroup = "";

                    for (int cptTst1 = 0; cptTst1 < cptApplicationGroups; cptTst1++)
                    {
                        // Create the group that will contains the application
                        if(applicationGroups.ElementAt(cptTst1).Attributes.GetNamedItem("name") != null)
                            nameGroup = applicationGroups.ElementAt(cptTst1).Attributes.GetNamedItem("name").InnerText;
                        else
                            nameGroup = "Application Group " + cptTst1;

                        if (applicationGroups.ElementAt(cptTst1).Attributes.GetNamedItem("description") != null)
                            descriptionGroup = applicationGroups.ElementAt(cptTst1).Attributes.GetNamedItem("description").InnerText;
                        else
                            descriptionGroup = "";


                        if (applicationGroups.ElementAt(cptTst1).Attributes.GetNamedItem("image") != null)
                        {
                            imageGroup = applicationGroups.ElementAt(cptTst1).Attributes.GetNamedItem("image").InnerText;
                            if (!Uri.IsWellFormedUriString(imageGroup, UriKind.Absolute))
                            {
                                if (imageGroup.ToUpper() == "WINDOWSSTORE")
                                    imageGroup = "Assets/WindowsStore.png";
                                else
                                {
                                    if (imageGroup.Contains(@"local\"))
                                    {
                                        imageGroup = Windows.Storage.ApplicationData.Current.LocalFolder.Path + @"\" + imageGroup.Substring(imageGroup.IndexOf(@"\") + 1);
                                    }
                                    else
                                    {
                                        imageGroup = "Assets/" + imageGroup;
                                    }
                                }
                            }
                            else
                            {
                                
                                imageGroup = applicationGroups.ElementAt(cptTst1).Attributes.GetNamedItem("image").InnerText;
                            }
                        }
                        else
                        {
                            imageGroup = "";
                        }

                        group = new SampleDataGroup(nameGroup, nameGroup, "", imageGroup, descriptionGroup);

                        //Fill the list of application for this group
                        nodeList = applicationGroups.ElementAt(cptTst1).ChildNodes;
                        cptApplication = nodeList.Count;
                        for (uint cptTst3 = 0; cptTst3 < cptApplication; cptTst3++ )
                        {
                            if (nodeList.Item(cptTst3).GetType().ToString() == "Windows.Data.Xml.Dom.XmlElement")
                            {
                                String name = "", logo = "", shotDesc = "", link = "", store = "" ;
                                //if the application have no name, we ignore it
                                if (nodeList.Item(cptTst3).SelectSingleNode("Name") != null)
                                {
                                    if (nodeList.Item(cptTst3).SelectSingleNode("Name").InnerText != "")
                                    {
                                        name = nodeList.Item(cptTst3).SelectSingleNode("Name").InnerText;

                                        if (nodeList.Item(cptTst3).SelectSingleNode("Logo") != null)
                                            if (nodeList.Item(cptTst3).SelectSingleNode("Logo").InnerText == "")
                                                logo = "Assets/LightBlue.png";
                                            else
                                            {
                                                logo = nodeList.Item(cptTst3).SelectSingleNode("Logo").InnerText.Replace("??", "&");
                                                if (!Uri.IsWellFormedUriString(logo, UriKind.Absolute))
                                                {
                                                    //if the logo is not a valid URI consider that the logo is in the assets folder
                                                    switch (logo)
                                                    {
                                                        case "skype-logo-graduated": logo = "Assets/skype-logo-graduated.jpg"; break;
                                                        case "Logo150x150": logo = "Assets/Logo150x150.png"; break;
                                                        case "MediumGreen": logo = "Assets/MediumGreen.png"; break;
                                                        case "LightPurple": logo = "Assets/LightPurple.png"; break;
                                                        case "LightBlue": logo = "Assets/LightBlue.png"; break;
                                                        case "lync15": logo = "Assets/Lync15.png"; break;
                                                        default: {
                                                            if(logo.Contains(@"local\")){
                                                                logo = Windows.Storage.ApplicationData.Current.LocalFolder.Path + @"\" + logo.Substring(logo.IndexOf(@"\")+1);
                                                            }
                                                            else {
                                                                logo = "Assets/" + logo;
                                                            }
                                                            break;
                                                        } 
                                                    }
                                                }
                                            }
                                        else
                                            logo = "Assets/LightBlue.png";

                                        if (nodeList.Item(cptTst3).SelectSingleNode("ShortDescription") != null)
                                            shotDesc = nodeList.Item(cptTst3).SelectSingleNode("ShortDescription").InnerText;
                                        else
                                        {
                                            shotDesc = "";
                                        }

                                        if (nodeList.Item(cptTst3).SelectSingleNode("HyperLink") != null)
                                            link = nodeList.Item(cptTst3).SelectSingleNode("HyperLink").InnerText.Replace("??", "&");
                                        else
                                            link = "";

                                        if (nodeList.Item(cptTst3).SelectSingleNode("MSStoreID") != null)
                                            store = nodeList.Item(cptTst3).SelectSingleNode("MSStoreID").InnerText;
                                        else
                                        {
                                            store = "";
                                        }

                                        group.Items.Add(new SampleDataItem(name,
                                            name,
                                            shotDesc,
                                            logo,
                                            link,
                                            store,
                                            group));
                                    }
                                }
                            }
                        }
                        this.AllGroups.Add(group);
                    }
                }
            }
        }

        public static async Task<String> getCompanyName()
        {
            if (file == null)
            {
                try
                {
                    file = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(App.ConfigurationFile);
                }
                catch (FileNotFoundException)
                {

                }

                //If there is no configuration file on the default location, read a demo one on the application package.
                // this is mostly used for a demo app in the Windows Store
                if (file == null)
                {
                    try
                    {
                        file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Assets\StoreStructure.xml");
                    }
                    catch (FileNotFoundException)
                    {

                    }
                }
            }
            
            if (file != null)
            {
                XmlDocument doc = null;
                try
                {
                    XmlLoadSettings settings = new XmlLoadSettings();
                    
                    doc = await XmlDocument.LoadFromFileAsync(file);
                    if (doc != null)
                    {
                        if (doc.SelectSingleNode("//xml").Attributes.GetNamedItem("companyName") != null)
                            return doc.SelectSingleNode("//xml").Attributes.GetNamedItem("companyName").InnerText;
                    }
                }
                catch (Exception)
                {
                    _error = App.errorXMLEncoding;
                }
            }
            
            return "";
        }

        internal static async Task loadSettings()
        {
            if (file == null)
            {
                try
                {
                    file = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(App.ConfigurationFile);
                }
                catch (FileNotFoundException)
                {

                }

                //If there is no configuration file on the default location, read a demo one on the application package.
                // this is mostly used for a demo app in the Windows Store
                if (file == null)
                {
                    try
                    {
                        file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Assets\StoreStructure.xml");
                    }
                    catch (FileNotFoundException)
                    {

                    }
                }
            }

            if (file != null)
            {
                XmlDocument doc = null;
                try
                {
                    doc = await XmlDocument.LoadFromFileAsync(file);
                    if (doc != null)
                    {
                        //Load Error messages
                        var Errors = doc.SelectNodes("//xml/Settings/ErrorMessages/Error");
                        if (Errors != null)
                        {
                            int cptErrors = Errors.Count;
                            for (uint i = 0; i < cptErrors; i++)
                            {
                                if (Errors.Item(i).Attributes.GetNamedItem("name").InnerText == "URIFormatException")
                                {
                                    App.errorURIMessage = Errors.Item(i).InnerText;
                                }
                            }
                        }

                        //Load Privacy Policy display value
                        var privacyVisibility = doc.SelectSingleNode("//xml/Settings/DisplayPrivacyPolicy");
                        if (privacyVisibility != null)
                            App.displayPrivacyPolicy = privacyVisibility.InnerText.Trim().ToUpper().CompareTo("NO") == 0 ? false : true;



                        //Load Storyboard layout main grid margin
                        //   this one is for compatibility, due to an error in previous release
                        var margin = doc.SelectSingleNode("//xml/Settings/StoryBoardLayout_GridMaring");
                        if (margin != null)
                            App.itemGridViewMargin = margin.InnerText.Trim();

                        margin = doc.SelectSingleNode("//xml/Settings/StoryBoardLayout_GridMargin");
                        if (margin != null)
                            App.itemGridViewMargin = margin.InnerText.Trim();

                    }
                }
                catch (Exception)
                {

                }
            }

            return;
        }


        public static String getError()
        {
            string result = _error;
            _error = null;
            return result;
        }

    }
}
